package com.duoec.doc.mock.config;

import com.duoec.doc.mock.dto.DuoMockRequest;
import com.duoec.doc.mock.service.MockSender;
import com.duoec.doc.mock.dto.DuoMockResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xuwenzhen
 */
@Configuration
@ConditionalOnWebApplication
public class MockInterceptor implements WebMvcConfigurer {
    private static final String CHARSET = "UTF-8";
    @Autowired
    private MockSender mockSender;

    @Autowired
    private DocMockConfig docMockConfig;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HandlerInterceptor() {
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                if (docMockConfig.getMockHeader() != null && !docMockConfig.getMockHeader()) {
                    //有配置，并且为false时，不走mock
                    return true;
                }


                String mock = request.getHeader("mock");
                if (mock == null) {
                    //请求头没有设置mock，但服务端强制要求，则不走mock
                    return true;
                }

                DuoMockRequest mockRequest = new DuoMockRequest();

                Enumeration<String> it = request.getHeaderNames();
                while (it.hasMoreElements()) {
                    String name = it.nextElement();
                    if (StringUtils.isEmpty(name)) {
                        continue;
                    }
                    mockRequest.addHeader(name, request.getHeader(name));
                }

                Map<String, String> pathVariables = new HashMap<>(8);
                Map<String, String> pathParams = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
                if (!CollectionUtils.isEmpty(pathParams)) {
                    pathParams.forEach((key, value) -> {
                        if (!StringUtils.isEmpty(key)) {
                            pathVariables.put(key, value);
                        }
                    });
                }

                //最佳命中路径
                String path = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
                Map<String, String[]> parameterMap = new HashMap<>();
                Map<String, String[]> paramMap = request.getParameterMap();
                if (!CollectionUtils.isEmpty(paramMap)) {
                    paramMap.forEach((key, value) -> {
                        if (!StringUtils.isEmpty(key)) {
                            parameterMap.put(key, value);
                        }
                    });
                }

                mockRequest.setPath(path);
                mockRequest.setPathParameterMap(pathVariables);
                mockRequest.setParameterMap(parameterMap);
                mockRequest.setUri(request.getRequestURI());
                mockRequest.setAppId(docMockConfig.getAppId());
                mockRequest.setMethod(request.getMethod());
                DuoMockResponse mockResponse = mockSender.mock(mockRequest);

                response.setCharacterEncoding(CHARSET);
                response.addHeader("Content-type", "application/json");
                if (mockResponse.getCode().equals(DuoMockResponse.SUCCESS_CODE)) {
                    // 响应成功
                    response.getWriter().print(mockResponse.getBody());
                } else {
                    response.setStatus(mockResponse.getCode());
                    response.getWriter().print(mockResponse.getMsg());
                }
                return false;
            }

            @Override
            public void afterCompletion(
                    HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex
            ) throws Exception {

            }
        }).addPathPatterns("/**");
    }
}
